using System;
using System.Collections.Generic;
using System.Text;
using System.Web;
using System.Configuration;
using System.Xml;
using System.Text.RegularExpressions;
using System.Web.UI;
using System.IO;
using System.Collections.Specialized;
using System.Reflection;

namespace ExtraClub.Domain {
    public partial class RewriteModule : IHttpModule {
        HttpContext Context;

        public void Init(HttpApplication context) {
            context.BeginRequest += new EventHandler(RewriteModule_BeginRequest);
            context.PreRequestHandlerExecute += new EventHandler(RewriteModule_PreRequestHandlerExecute);
        }

        private void RewriteModule_BeginRequest(object sender, EventArgs e) {
            RewriteModuleSectionHandler cfg = (RewriteModuleSectionHandler)ConfigurationManager.GetSection("rewriteModule");
            if (cfg.RewriteOn) {
                /*
                 * if (!page.Exists && !default){
                        url.aspx -> /default.aspx?page=url
                 * }
                */
                Context = HttpContext.Current;
                string path = Context.Request.Path.ToLower();

                if (!File.Exists(Context.Server.MapPath(path))) {
                    XmlNode rules = cfg.XmlSection.SelectSingleNode("rewriteRules");

                    foreach (XmlNode xml in rules.SelectNodes("rule")) {
                        try {
                            Regex rex = new Regex(xml.Attributes["source"].InnerText, RegexOptions.IgnoreCase | RegexOptions.Multiline);
                            Match match = rex.Match(path);
                            if (match.Success) {

                                XmlAttribute dest = xml.Attributes["destination"];
                                XmlAttribute rule = xml.Attributes["value"];

                                if (dest != null) {
                                    path = rex.Replace(path, dest.Value);
                                } else if (rule != null) {
                                    path = this.GetType().InvokeMember(rule.Value, BindingFlags.NonPublic |
                                        BindingFlags.Static |
                                        BindingFlags.InvokeMethod, null, this, new object[] { rex, path }) as String;
                                }

                                if (!string.IsNullOrEmpty(path)) {
                                    if (Context.Request.QueryString.Count != 0) {
                                        string sign = (path.IndexOf('?') == -1) ? "?" : "&";
                                        path = path + sign + Context.Request.QueryString.ToString();
                                    }

                                    Context.Items.Add("OriginalUrl", Context.Request.RawUrl);
                                    Context.RewritePath(cfg.RewriteBase + path);
                                } else {
                                    break;
                                }
                            }
                        } catch (Exception ex) {
                            throw (new Exception("Incorrect rule. Path:" + path, ex));
                        }
                    }
                }
            }
        }

        #region Routines

        void RewriteModule_PreRequestHandlerExecute(object sender, EventArgs e) {
            HttpApplication app = (HttpApplication)sender;
            if ((app.Context.CurrentHandler is Page) && app.Context.CurrentHandler != null) {
                Page pg = (Page)app.Context.CurrentHandler;
                pg.PreInit += new EventHandler(Page_PreInit);
            }
        }

        void Page_PreInit(object sender, EventArgs e) {
            // restore internal path to original
            // this is required to handle postbacks
            if (HttpContext.Current.Items.Contains("OriginalUrl")) {
                string path = (string)HttpContext.Current.Items["OriginalUrl"];

                // save query string parameters to context              
                RewriteContext con = new RewriteContext(HttpContext.Current.Request.QueryString, path);
                HttpContext.Current.Items["RewriteContextInfo"] = con;

                if (path.IndexOf("?") == -1) {
                    path += "?";
                }

                HttpContext.Current.RewritePath(path);
            }
        }
        public void Dispose() { }
        #endregion
    }
}